#include "md5.h"
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

char *to_hexa(md5_byte_t *digest, size_t len);

char *to_hexa(md5_byte_t *digest, size_t len) {
	unsigned int i = 0;
	char *result = NULL;
	
	result = calloc(len*2 + 1, sizeof(char));
	
	for (i = 0; result != NULL && i < len; ++i) {
		sprintf(result + i * 2, "%02x", digest[i]);
	}
	
	return result;
}

#define BUFF 256
#define MIN(a,b) ((a<b)?a:b)

int main(int argc, char *argv[]) {
	md5_state_t state;
	md5_byte_t digest[16], content[BUFF];
	char *hexa = NULL;
	FILE *f = NULL;
	struct stat stat_res;
	int read_res = 0;
	int i = 0, j = 0;

	assert(argc == 2);
	assert(argv[1] != NULL);
	f = fopen(argv[1], "r");
	assert(f != NULL);

	fstat(fileno(f), &stat_res);
	i = stat_res.st_size;
#ifdef _DEBUG
	fprintf(stderr, "size: %i\n", i);
#endif

	md5_init(&state);

	do {
		j = MIN(i,BUFF);
#ifdef _DEBUG
	fprintf(stderr, "j: %i\n", j);
#endif
		assert(!feof(f));
		read_res = fread(&content, sizeof(md5_byte_t), j, f);
#ifdef _DEBUG
	fprintf(stderr, "read_res: %i, i: %i\n", read_res, i);
#endif
		assert(read_res == j);
		md5_append(&state, (const md5_byte_t *)content, j);
		i -= j;
	} while (i > 0);

	md5_finish(&state, digest);
	fclose(f);

	hexa = to_hexa(digest, 16);
	printf("Result: %s\n", hexa);
	free(hexa);

	return 0;
}
